import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.HashUtil;
import cn.hutool.core.util.RandomUtil;

import java.awt.*;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public class CouponCodeGenerator {

    private static final SecureRandom random = new SecureRandom();
    private static final int MIN_LENGTH = 6;
    private static final int MAX_LENGTH = 12;

    // 假设这个方法用于检查数据库中是否已存在该券码  
    private boolean isCodeExisting(String code) {
        // 这里应该是数据库查询逻辑  
        // 返回true如果券码已存在，否则返回false  
        return !cacheCodes.add(code); // 示例中假设所有券码都不存在
    }

    // 生成券码的方法  
    public String generateCouponCode(String businessOrProductId) {
        String code = "";
        int length = MIN_LENGTH + random.nextInt(MAX_LENGTH - MIN_LENGTH + 1); // 随机长度

        // 如果业务号码或商品号码长度合适，尝试将其包含在内  
        if (businessOrProductId != null && businessOrProductId.matches("\\d+") && businessOrProductId.length() <= length - 3) {
            code = businessOrProductId;
            length -= businessOrProductId.length();
        }

        // 填充剩余部分，避免使用容易混淆的数字组合（这里简化处理）  
        for (int i = 0; i < length; i++) {
            int digit = random.nextInt(10);

//            if (digit == 0 && (code.isEmpty() || length > 1)) {
//                digit = 1; // 或者选择其他非0数字
//            }
            // 这里可以添加更复杂的逻辑来进一步避免混淆  
            code += digit;
        }

        // 检查生成的券码是否已存在，如果存在则重新生成  
        while (isCodeExisting(code)) {
            System.out.println("重复");
            return generateCouponCode(code);
//            code = ""; // 重置券码
//            length = MIN_LENGTH + random.nextInt(MAX_LENGTH - MIN_LENGTH + 1); // 重新随机长度
            // 重新生成券码逻辑...  
            // 注意：这里为了简化示例，没有重新实现完整的生成逻辑  
            // 在实际应用中，您应该重新调用此方法的内部逻辑来生成新的券码  
        }

        return code;
    }

    public String randomStr(int size) {
        String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < size; ++i) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    public String code2() {
        String randomStr = randomStr(12);
//            System.out.println(randomStr);
        byte[] bytes = (randomStr).getBytes(StandardCharsets.UTF_8);
        StringBuilder code = new StringBuilder();
        for (byte aByte : bytes) {
//                System.out.println(aByte);
            char[] nums = Integer.toString(aByte).toCharArray();
            char n = nums[random.nextInt(nums.length - 1)];
            code.append(n);
        }
        if (!cacheCodes.add(code.toString())) {
            System.out.println("重复");
            return code2();
        }

        return code.toString();
    }

    Set<String> cacheCodes = new HashSet<>();
    long seq = 1;
    int cached = 0;
    long sta = 999999999999L;

    public long getRandomLong(long min, long max) {
        return min + random.nextLong() % (max - min + 1);
    }

    //因为凑总共40位，但十进制12位
    long randomBits = 24L;
    long workId = 5L;
    long seqBits = 5L;
    long businessBits = 3L;

    public String code3(long businessId) {
        long r = random.nextInt(30517577) + 1;

        String code = (r << 15 | (seq & 4095L) << 3 | businessId) + "";

        if (!cacheCodes.add(code)) {
            cached++;
            return code3(businessId);
        }
        seq += 1;
        if (seq > 4095L) {
            seq = 1;
        }

        return code;
    }

    public String code33(long businessId) {
        long r = random.nextInt(9999999 + 1);
        long now = System.currentTimeMillis();
        long dif = (now % (sta + 1));
        long c1 = r << 16 | (seq & 8191L) << 3 | businessId;
        long c2 = Math.min(dif, (sta - c1));
        if (c2 != dif) {
            c2 = getRandomLong(0, c2);
        }
        String code = (c1 | c2) + "";

        if (!cacheCodes.add(code)) {
            cached++;
            return code3(businessId);
        }
        seq += 1;
        if (seq > 8191L) {
            seq = 1;
        }

        return code;
    }


    public String code4(int businessId) {
        String code = RandomUtil.randomLong(1, sta + 1) + "";
//        int diffLength = 12 - code.length();

        if (!cacheCodes.add(code)) {
            cached++;
            return code4(businessId);
        }

        return code;
    }


    public static void main(String[] args) {
        CouponCodeGenerator generator = new CouponCodeGenerator();
//        for (int i = 0; i < 4096; i++) {
//            String code = generator.generateCouponCode("1"); // 假设业务号码或商品号码为"12345"
//            generator.cacheCodes.put(code, code);
//            System.out.println("Generated Coupon Code: " + code);
//        }

//        for (int i = 0; i < 4096; i++) {
//            String code =generator.code2();
//            generator.cacheCodes.put(code, "1");
//            System.out.println(code);
//        }

//
//24<<(13+3)
        //1110100011010100101001010000111111111111
//        System.out.println(-1L ^ (-1L << 40L));
//        System.out.println(-1L ^ (-1L << 24L));
//        System.out.println(-1L ^ (-1L << 13L));
//        System.out.println(-1L ^ (-1L << 3L));
        
        StopWatch watch = StopWatch.create("1");
        watch.start();
//        int[] type = {1, 2, 3, 4};
//        for (int i = 0; i < 2000000; i++) {
//            String code = generator.code3(type[random.nextInt(4)]);
//            generator.cacheCodes.add(code);
//            System.out.println(code);
//        }

//        for (int i = 0; i < 2000000; i++) {
//            String code = generator.code4(0);
//            generator.cacheCodes.add(code);
//            System.out.println(code);
//        }

        watch.stop();
        System.out.println(generator.cached);
        System.out.println(watch.prettyPrint(TimeUnit.MILLISECONDS));

        // 随机数补位 没意思 放弃
//        long[] a = {100000000000L, 200000000000L, 300000000000L, 400000000000L};
//        long[] b = {899999999999L, 799999999999L, 699999999999L, 599999999999L};
//        int idx = random.nextInt(3);
//        System.out.println(random.nextDouble());
//        System.out.println(a[idx] + (long) (random.nextDouble() * b[idx]));

        // 随机数
//        long iii = 999999999999L;
//        for (int i = 0; i < 10000; i++) {
//            System.out.println(RandomUtil.randomLong(1, iii + 1));
//        }
    }
}